<script setup>
  import { computed, ref, watch } from 'vue'
  import 'leaflet/dist/leaflet.css'
  import {
    LIcon,
    LMap,
    LMarker,
    LTileLayer,
  } from '@vue-leaflet/vue-leaflet'
    import L from 'leaflet'

  import { useConstStore } from '@/stores/const'
  import BooleanCheckbox from '@/components/forms/BooleanCheckbox.vue'
  import IconSpan from '@/components/IconSpan.vue'

  /** Mini map for lat-lon selection using LeafLet
   */
  const props = defineProps({
      label: { type: String, default: '' },
      ariaLabel: { type: String, default: '' },
      value: {type: Array, default: [47.21297, -1.55104]},
      editable: { type: Boolean, default: true },
      description: {type: String, default: 'Vous pouvez déplacer le marqueur pour ajuster la position.'},
      fallbackCenter: { type: Array, required: true },
      checkboxLabel: {
        type: String,
        default: 'Définir une localisation',
      },
      checkboxDescription: { type: String, default: '' },
  })
  const emits = defineEmits([
    'changeValue',
    'checkboxToggled',
  ])

  // STORES
  const constStore = useConstStore()
  const endiConfig = ref({})
  endiConfig.value = await constStore.loadConst('config')

  // INTERNAL STATE
  const currentValue = ref(L.latLng(props.value))
  const isMarkerPositioned = computed(
    () => Boolean(currentValue.value && currentValue.value.lat)
  )
  // When displaying the default position we have a difference between
  // the displayed marker (set to fallbackCenter) and the actual value
  // (which remains null-ish until the marker is moved by user)
  const markerDisplayedPosition = computed(
    () => isMarkerPositioned.value ? currentValue.value : L.latLng(props.fallbackCenter)
  )
  const mapCenter = ref(markerDisplayedPosition.value)

  // UTILS
  const travelToMarker = () => mapCenter.value = markerDisplayedPosition.value

  // EVENTS
  // Will trigger wether marker is moved manually or via onMarkerToggle
  const onMarkerMoved = (latLng) =>  {
    if (currentValue.value) {
      currentValue.value = latLng
    }
    // may be a LatLng or null
    emits("changeValue", currentValue.value)
  }
  const onMarkerToggle = async event => {
    const checked = event.target.checked
    await emits("checkboxToggled", checked)
    if (checked) {
      currentValue.value = L.latLng(props.fallbackCenter)
      travelToMarker()
      // Workaround grey tiles after showing the map previously hidden
      // https://stackoverflow.com/a/65555639/1377500
      window.setTimeout(() => window.dispatchEvent(new Event('resize')), 500)
    } else {
      currentValue.value = null
    }
  }
  // If prop change, we overwrite local value and move viewport to it
  watch(() => props.value, () => {
    currentValue.value = L.latLng(props.value)
    travelToMarker()
  })
</script>

<template>
  <div class='form-group'>
    <span class='label'>{{ label }}</span>
    <div v-show='isMarkerPositioned'>
      <LMap :center='mapCenter'
            :zoom='12'
            style='height: 350px'
      >
        <l-tile-layer
          :url='endiConfig.leaflet_layer_url'
          attribution='&copy; Contributeur·ices <a target="_blank" href="http://osm.org/copyright">OpenStreetMap</a>'
        />
        <LMarker :lat-lng='markerDisplayedPosition' :draggable='editable'
                 @update:lat-lng='onMarkerMoved'>
          <LIcon>
            <IconSpan name='location-dot' css-class='map_location' alt="Localisation de l'enseigne" />
          </LIcon>
        </LMarker>
      </LMap>
      <div class='help-block' v-if='description' v-html='description' />
    </div>
    <BooleanCheckbox
      :value='isMarkerPositioned'
      name='show_me_on_map'
      :label='checkboxLabel'
      :description="checkboxDescription"
      @change='onMarkerToggle'
    />
  </div>
</template>
